package com.tender;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EasyTestAdvance4API {

    @Test
    public void test01() {
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RuntimeService对象
        RuntimeService runtimeService = engine.getRuntimeService();
        // 3.启动流程实例
        String businessKey = "1002";
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("tender_evection", businessKey);
        // 4.输出processInstance相关属性
        System.out.println("businessKey = " + instance.getBusinessKey());
    }

    /**
     * 全部流程挂起实例与激活
     */
    @Test
    public void test02() {
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService对象
        RepositoryService repositoryService = engine.getRepositoryService();
        // 3.查询流程定义的对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("tender_evection")
                .singleResult();
        // 4.获取当前流程定义的状态
        boolean suspended = processDefinition.isSuspended();
        System.out.println("当前流程定义的状态： " + suspended);
        System.out.println("当前流程定义的状态 = " + (suspended ? "挂起" : "未挂起"));
        String id = processDefinition.getId();
        System.out.println("当前流程定义的id： " + id);
        // 5.如果挂起就激活，如果激活就挂起
        if (suspended) {
            // 表示当前定义的流程状态是 挂起的
            repositoryService.activateProcessDefinitionById(
                    id // 流程定义的id
                    , true // 是否激活
                    , null // 激活时间
            );
            System.out.println("流程定义：" + id + ",已激活");
        } else {
            // 非挂起状态，激活状态 那么需要挂起流程定义
            repositoryService.suspendProcessDefinitionById(
                    id // 流程id
                    , true // 是否挂起
                    , null // 挂起时间
            );
            System.out.println("流程定义：" + id + ",已挂起");
        }
    }

    /**
     * 单个流程实例挂起与激活
     */
    @Test
    public void test03() {
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RuntimeService
        RuntimeService runtimeService = engine.getRuntimeService();
        // 3.获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                // 可以从 act_ru_task 中的 PROC_INST_ID_ 获取流程实例id
                .processInstanceId("12501")
                .singleResult();
        // 4.获取相关的状态操作
        boolean suspended = processInstance.isSuspended();
        System.out.println("当前流程定义的状态： " + suspended);
        System.out.println("当前流程定义的状态 = " + (suspended ? "挂起" : "未挂起"));
        String id = processInstance.getId();
        System.out.println("当前流程定义的id： " + id);
        if (suspended) {
            // 挂起 -> 激活
            runtimeService.activateProcessInstanceById(id);
            System.out.println("流程实例：" + id + "，已激活");
        } else {
            // 激活 -> 挂起
            runtimeService.suspendProcessInstanceById(id);
            System.out.println("流程实例：" + id + "，已挂起");
        }
    }

    /**
     * 用于 UEL 测试
     * 先将新定义的流程部署到Activiti中数据库中
     */
    @Test
    public void test04() {
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService进行部署操作
        RepositoryService service = engine.getRepositoryService();
        // 3.使用RepositoryService进行部署操作
        // 如果找不到资源报错了，则需要执行 mvn install
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/tender_evection_UEL.bpmn") // 添加bpmn资源
                .addClasspathResource("bpmn/tender_evection_UEL.png") // 添加png资源
                .name("出差申请流程-UEL")
                .deploy();// 部署流程
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称：" + deploy.getName());
    }

    /**
     * 用于 UEL 测试
     * 创建一个流程实例
     * 给流程定义中的 UEL表达式赋值
     */
    @Test
    public void test05() {
        // 获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取RuntimeService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 设置 assignee 的取值，
        Map<String, Object> map = new HashMap<>();
        map.put("hr_assignee", "hr_tender");
        map.put("manager_assignee", "manager_tender");
        // 创建流程实例
        // 流程定义id 可以从 act_re_procdef 表里面的 KEY_ 字段查看到，或者流程模型定义的时候也能看到
        runtimeService.startProcessInstanceByKey("tender_evection_UEL", map);
    }

    /**
     * 用于 task listener 测试
     * 先将新定义的流程部署到Activiti中数据库中
     */
    @Test
    public void test06() {
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService进行部署操作
        RepositoryService service = engine.getRepositoryService();
        // 3.使用RepositoryService进行部署操作
        // 如果找不到资源报错了，则需要执行 mvn install
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/tender_evection_listener.bpmn") // 添加bpmn资源
                .addClasspathResource("bpmn/tender_evection_listener.png") // 添加png资源
                .name("出差申请流程-listener")
                .deploy();// 部署流程
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称：" + deploy.getName());
    }

    /**
     * 用于 task listener 测试
     * 创建一个流程实例
     * 利用 task listener 来指定 assignee
     */
    @Test
    public void test07() {
        // 获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取RuntimeService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 创建流程实例
        // 流程定义id 可以从 act_re_procdef 表里面的 KEY_ 字段查看到，或者流程模型定义的时候也能看到
        runtimeService.startProcessInstanceByKey("tender_evection_listener", "9999");
    }


    // 查询当前个人待执行的任务
    @Test
    public void findPersonalTaskList() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 流程定义key
        String processDefinitionKey = "tender_evection_listener";
        // 任务负责人
        String assignee = "hr_tender_Listener";
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .includeProcessVariables()
                .taskAssignee(assignee)
                .list();
        for (Task task : taskList) {
            System.out.println("----------------------------");
            System.out.println("流程实例id： " + task.getProcessInstanceId());
            System.out.println("任务id： " + task.getId());
            System.out.println("任务负责人： " + task.getAssignee());
            System.out.println("任务名称： " + task.getName());
        }

        /**
         * ----------------------------
         * 流程实例id： 22501
         * 任务id： 22505
         * 任务负责人： hr_tender_Listener
         * 任务名称： 人事审批
         */
    }

    /**
     * 查询 businessKey
     */
    @Test
    public void findProcessInstance() {
        // 获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取TaskService
        TaskService taskService = processEngine.getTaskService();
        // 获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 查询流程定义的对象
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("tender_evection_listener")
                .taskAssignee("hr_tender_Listener")
                // .processInstanceBusinessKey("9999")
                .singleResult();
        // 使用task对象获取实例id
        String processInstanceId = task.getProcessInstanceId();
        // 使用实例id，获取流程实例对象
        ProcessInstance processInstance =
                runtimeService.createProcessInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .singleResult();
        // 使用processInstance，得到 businessKey
        String businessKey = processInstance.getBusinessKey();
        System.out.println("businessKey = " + businessKey);
    }

    /**
     * 完成任务，判断当前用户是否有权限
     */
    @Test
    public void completeTask() {
        //任务id
        String taskId = "22505";
        // 任务负责人
        String assingee = "hr_tender_Listener";
        //获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 创建TaskService
        TaskService taskService = processEngine.getTaskService();
        // 完成任务前，需要校验该负责人可以完成当前任务
        // 校验方法：
        // 根据任务id和任务负责人查询当前任务，如果查到该用户有权限，就完成
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assingee)
                .singleResult();
        if (task != null) {
            // taskService.complete(taskId);
            // System.out.println("完成任务");
            System.out.println("有任务待处理");
        }
    }

    /**
     * 用于 variables 测试使用
     * 部署流程
     */
    @Test
    public void testBpmnProcessDeploymentWithVariables() {
        // 1.获取ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService进行部署操作
        RepositoryService service = engine.getRepositoryService();
        // 3.使用RepositoryService进行部署操作
        Deployment deploy = service.createDeployment()
                .addClasspathResource("bpmn/tender_evection_variables.bpmn") // 添加bpmn资 源
                .addClasspathResource("bpmn/tender_evection_variables.png") // 添加png资源
                .name("出差申请流程-variables")
                .deploy();// 部署流程
        // 4.输出流程部署的信息
        System.out.println("流程部署的id:" + deploy.getId());
        System.out.println("流程部署的名称：" + deploy.getName());
    }

    /**
     * 用于 variables 测试使用
     * 启动流程实例，设置流程变量
     */
    @Test
    public void testStartProcessInstanceWithVariables() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 流程定义key
        String key = "tender_evection_variables";
        // 创建变量集合
        Map<String, Object> variables = new HashMap<>();
        // 创建出差对象 POJO
        Evection evection = new Evection();
        // 设置出差天数
        evection.setNum(4d);
        // 将定义的出差对象 evection 放到集合中
        variables.put("evection", evection);
        // 设置assignee的取值
        variables.put("creater_assignee", "creater_tender");
        variables.put("manager_assignee", "manager_tender");
        variables.put("general_mgr_assignee", "general_mgr_tender");
        variables.put("financial_assignee", "financial_tender");
        // 启动实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables);
        // 输出信息
        System.out.println("获取流程实例名称：" + processInstance.getName());
        System.out.println("流程定义ID：" + processInstance.getProcessDefinitionId());
    }

    /**
     * 用于 variables 测试使用
     * 完成任务
     */
    @Test
    public void testCompleteTaskWithVariables() {
        String key = "tender_evection_variables";
        // assignee 从 creater_tender 到 manager_tender
        // String assignee = "creater_tender";
        String assignee = "manager_tender";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();
        if (task != null) {
            taskService.complete(task.getId());
            System.out.println("任务执行完成...");
        }
    }

    /**
     * 用于 variables 测试使用，在完成任务的时候，设置流程变量
     * 启动流程实例，设置流程变量
     */
    @Test
    public void testStartProcessInstanceWithVariables02() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();
        // 流程定义key
        String key = "tender_evection_variables";
        // 创建变量集合
        Map<String, Object> variables = new HashMap<>();
        // 设置assignee的取值
        variables.put("creater_assignee", "creater_tender02");
        variables.put("manager_assignee", "manager_tender02");
        variables.put("general_mgr_assignee", "general_mgr_tender02");
        variables.put("financial_assignee", "financial_tender02");
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables);
        // 输出信息
        System.out.println("获取流程实例名称：" + processInstance.getName());
        System.out.println("流程定义ID：" + processInstance.getProcessDefinitionId());
    }

    /**
     * 用于 variables 测试使用，在完成任务的时候，设置流程变量
     * 完成任务
     */
    @Test
    public void testCompleteTaskWithVariables02() {
        String key = "tender_evection_variables";
        // String assignee = "creater_tender02";
        String assignee = "manager_tender02";
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .singleResult();
        Map<String, Object> variables = new HashMap<>();
        // 创建出差对象 POJO
        Evection evection = new Evection();
        // 设置出差天数
        evection.setNum(4d);
        // 定义流程变量到集合中
        variables.put("evection", evection);
        if (task != null) {
            taskService.complete(task.getId(), variables);
            System.out.println("任务执行完成...");
        }
    }


    @Test
    public void setGlobalVariableByExecutionId() {
        // 当前流程实例执行 id，通常设置为当前执行的流程实例
        String executionId = "37506";
        // 获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 创建出差pojo对象
        Evection evection = new Evection();
        // 设置天数
        evection.setNum(3d);
        // 通过流程实例 id设置流程变量
        runtimeService.setVariable(executionId, "evection", evection);
        // 一次设置多个值
        // runtimeService.setVariables(executionId, variables)
    }

    @Test
    public void setGlobalVariableByTaskId() {
        //当前待办任务id
        String taskId = "1404";
        // 获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Evection evection = new Evection();
        evection.setNum(3);
        //通过任务设置流程变量
        taskService.setVariable(taskId, "evection", evection);
        //一次设置多个值
        //taskService.setVariables(taskId, variables)
    }


    /*
     *处理任务时设置local流程变量
     */
    @Test
    public void setLocalVariablesWhenCompleteTask() {
        //任务id
        String taskId = "1404";
        // 获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 定义流程变量
        Map<String, Object> variables = new HashMap<String, Object>();
        Evection evection = new Evection();
        evection.setNum(3d);
        // 变量名是holiday，变量值是holiday对象
        variables.put("evection", evection);
        // 设置local变量，作用域为该任务
        taskService.setVariablesLocal(taskId, variables);
        // 完成任务
        taskService.complete(taskId);
    }

    @Test
    public void setLocalVariableByTaskId() {
        // 当前待办任务id
        String taskId = "1404";
        // 获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Evection evection = new Evection();
        evection.setNum(3d);
        // 通过任务设置流程变量
        taskService.setVariableLocal(taskId, "evection", evection);
        // 一次设置多个值
        //taskService.setVariablesLocal(taskId, variables)
    }

    /**
     * 查询历史任务的同时，带出历史任务对应的本地 local variables
     */
    @Test
    public void testQueryHistoryWithLocalVariables() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        HistoryService historyService = processEngine.getHistoryService();
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .includeTaskLocalVariables();
        List<HistoricTaskInstance> list = historicTaskInstanceQuery.list();
        for (HistoricTaskInstance historicTaskInstance : list) {
            System.out.println("==============================");
            System.out.println("任务id：" + historicTaskInstance.getId());
            System.out.println("任务名称：" + historicTaskInstance.getName());
            System.out.println("任务负责人：" + historicTaskInstance.getAssignee());
            System.out.println("任务local变量：" + historicTaskInstance.getTaskLocalVariables());
        }
    }
}
